package com.tqjc.execute.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hazelcast.client.map.impl.querycache.subscriber.QueryCacheToListenerMapper;
import com.tqjc.plccontrol.entity.ConnectInfo;
import com.tqjc.plccontrol.entity.DataMidEntity;
import com.tqjc.plccontrol.entity.PointInfo;
import com.tqjc.plccontrol.service.ConnectInfoService;
import com.tqjc.plccontrol.service.PlcInfoService;
import com.tqjc.plccontrol.service.PointInfoService;
import com.tqjc.plccontrol.utils.PlcResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.reactive.AbstractReactiveTransactionManager;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: TODO
 * @author: pzy
 * @date: 2023年05月18日 17:09
 */
@Slf4j
@Component
public class PlcOperator {


    @Resource
    PointInfoService pointInfoService;


    private final static String ACQUISITION_URL = "http://192.168.10.10";
    //    private final static String ACQUISITION_URL = "http://localhost";
//    private final static String ACQUISITION_URL = "http://10.168.16.95";
    private final static String WRITE_DATA_URL = ACQUISITION_URL + "/Api/Data/Write";
    private final static String READ_DATA_URL = ACQUISITION_URL + "/Api/Data/Read";
    private final static String READ_DATA_URL_BC = ACQUISITION_URL + "/Api/Data/Readbc";
    private final static String WRITE_DATA_URL_BC = ACQUISITION_URL + "/Api/Data/Writebc";
    private final static String READ_ALL_PLC = ACQUISITION_URL + "/Api/Data/Readsbca";


    @Value("${server_host}")
    private String serverHost;

    @Autowired
    private RestTemplate restTemplate;

    public  boolean upperCraneIsEnter(String craneType){  //上层行车是否已闯入
        String isEnter= null;
        try {
            isEnter = HttpPLCUtils.plcReadbc(restTemplate,serverHost,craneType,"上层行车闯入",false);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if("TRUE".equalsIgnoreCase(isEnter)){
            return true;
        }
        return false;
    }

    public  boolean personIsEnter(String craneType){  //人员是否闯入
        String isEnter= null;
        try {
            isEnter = HttpPLCUtils.plcReadbc(restTemplate,serverHost,craneType,"人员闯入",false);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if("TRUE".equalsIgnoreCase(isEnter)){
            return true;
        }
        return false;
    }

    public boolean checkIsSuckedSteel(String craneType){      //必须显示在界面上：天车正处于吸板状态
        //在停电情况下，如果恢复电后，判断天车是否吸板，如果是吸板，就不让启动。
        String isSucked= null;
        try {
            isSucked = HttpPLCUtils.plcReadbc(restTemplate,serverHost,craneType,"吊具有板",false);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if("true".equalsIgnoreCase(isSucked)){
            return true;
        }
        return false;
    }

    public String readPoint(String point) {
        QueryWrapper<PointInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", point);
        List<PointInfo> pointInfos = pointInfoService.list(queryWrapper);
        if (pointInfos.size() > 0) {
            PlcResult plcResult = readPlcValueBc(pointInfos.get(0).getName(), pointInfos.get(0).getConnectSn());
            if (plcResult.isSuccess()) {
                return plcResult.getData().toString();
            }
        }
        return null;
    }




    public static PlcResult<String> readPlcValueBc(String name, String sn) {

        //封装参数
        Map<String, String> param = new HashMap<>();
        param.put("sn", sn);
        param.put("label", name);

        String jsonString = JSONObject.toJSONString(param);

        PlcResult plcResult = PlcResult.fail("操作失败");
//            计数器 未成功重试
        Integer count = 3;
        while (count > 0) {
            //请求后台采集系统
            plcResult = sendHttpPost(READ_DATA_URL_BC, jsonString);
//            sendPost(READ_DATA_URL_BC, jsonString);
            if (plcResult.isSuccess()) {
                break;
            }
            count--;
        }
        if (plcResult.isSuccess()) {
            JSONObject jsonObject = JSONObject.parseObject(plcResult.getData().toString(), JSONObject.class);
            boolean success = Boolean.parseBoolean(jsonObject.getString("result"));
            if (success) {
                JSONObject content = jsonObject.getJSONObject("content");
                String currentVal = content.getString("currentVal");
                return PlcResult.ok(currentVal);
            }
            log.error("数采未返回结果！");
            return PlcResult.fail("数采未返回结果！");
        }
        //判断访问是否成功
        log.error("读取数据失败,请检查参数和配置！");
        return PlcResult.fail("读取数据失败,请检查参数和配置！");

    }


    public void writePlcValueBc(String value, Integer dateType, String macSn, String address) {

        //封装参数
        Map<String, Object> param = new HashMap<>();
        param.put("mac_sn", macSn);
        param.put("address", address);
        param.put("data_type", dateType);
        param.put("values", value);

        String jsonString = JSONObject.toJSONString(param);

        PlcResult plcResult = PlcResult.fail("操作失败");
//            计数器 未成功重试
        Integer count = 3;
        while (count > 0) {
            //请求后台采集系统
            plcResult = sendHttpPost(WRITE_DATA_URL_BC, jsonString);
//            sendPost(READ_DATA_URL_BC, jsonString);
            if (plcResult.isSuccess()) {
                JSONObject jsonObject = JSONObject.parseObject(plcResult.getData().toString(), JSONObject.class);
                boolean success = Boolean.parseBoolean(jsonObject.getString("result"));
                if (success) {
                    log.info("写入成功");
                    break;
                }
                log.error("数采写入失败,重试！");

            }
            count--;
        }

        //判断访问是否成功
        log.error("写入数据失败,请检查参数和配置！");

    }


    public PlcResult<Map<String, String>> readSbca(String connectSn) {

        List<PointInfo> pointList = new ArrayList<>();
        QueryWrapper<PointInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("connect_sn", connectSn);
        pointList = pointInfoService.list(queryWrapper);
        List<String> pointSns = pointList.stream().map(PointInfo::getSn).collect(Collectors.toList());

        //封装参数
        Map<String, Object> param = new HashMap<>();
        param.put("sn", connectSn);
        param.put("point_sns", pointSns);

        String jsonString = JSONObject.toJSONString(param);
        PlcResult plcResult = PlcResult.fail("操作失败");
//            计数器 未成功重试
        Integer count = 3;
        while (count > 0) {
            //请求后台采集系统
            plcResult = sendHttpPost(READ_ALL_PLC, jsonString);
            if (plcResult.isSuccess()) {
                break;
            }
            count--;
        }

        if (plcResult.isSuccess()) {
            JSONObject jsonObject = JSONObject.parseObject(plcResult.getData().toString(), JSONObject.class);
            try {
                boolean success = Boolean.parseBoolean(jsonObject.getString("result"));
                if (success) {
                    List<DataMidEntity> list = JSONArray.parseArray(JSON.toJSONString(jsonObject.get("content")), DataMidEntity.class);
                    Map<String, String> datas = new HashMap<>();
                    for (int i = 0; i < list.size(); i++) {
                        datas.put(list.get(i).getLabel(), list.get(i).getCurrentVal());
                    }
                    return PlcResult.ok(datas);
                }
                log.error("数采未返回结果！");
                return PlcResult.fail("数采未返回结果！");
            } catch (NullPointerException e) {
                log.error("PLC连接失败");
                return PlcResult.fail("PLC连接失败");
            }
        }
        //判断访问是否成功
        log.error("读取数据失败,请检查参数和配置！");
        return PlcResult.fail("读取数据失败,请检查参数和配置！");
    }

    public void writeValueByLabelAndCraneType(String name, String value, String craneType) {

        String label = craneType + name;

        //配置Querywrapper
        QueryWrapper<PointInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", label);
        List<PointInfo> pointInfos = pointInfoService.list(queryWrapper);

        if (pointInfos.size() > 0) {
            PointInfo pointInfo = pointInfos.get(0);
            writePlcValueBc(value, pointInfo.getDataType(), pointInfo.getMacSn(), pointInfo.getAddress());

        }
    }

    public String readValueByLabelAndCraneType(String name, String craneType) {

        String label = craneType + name;

        return readValueByLabel(label);
    }

    public String readValueByLabel(String label) {
        //配置Querywrapper
        QueryWrapper<PointInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", label);
        List<PointInfo> pointInfos = pointInfoService.list(queryWrapper);

        if (pointInfos.size() > 0) {
            PointInfo pointInfo = pointInfos.get(0);
            PlcResult plcResult = readPlcValueBc(label, pointInfo.getConnectSn());
            if (plcResult.isSuccess()) {
                return String.valueOf(plcResult.getData());
            }

        }
        return null;
    }

    /**
     * 发送HTTP请求
     *
     * @param url
     * @param JSONBody
     * @return
     */
    private static PlcResult sendHttpPost(String url, String JSONBody) {
        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("Content-Type", "application/json");
            httpPost.setEntity(new StringEntity(JSONBody, "UTF-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String responseContent = EntityUtils.toString(entity, "UTF-8");
            response.close();
            httpClient.close();
            return PlcResult.ok(responseContent);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return PlcResult.fail("数据采集返回失败");
    }

    public static void writePoint(String point) {
        System.out.println("写入成功");
    }

    public static Integer getNowCraneX(String craneType) {
        return null;
    }


    public static Integer getNowCraneY(String craneType) {
        return null;
    }

}
